/******************************************************************************
*	cmQueue.c	Code file of CM Queue Module.
*
*	coypright (C) 2009 Ding Lixing
*
******************************************************************************/

#include "cm.h"


struct cmQueueParam_typ {
    unsigned long msg;
};
typedef struct cmQueueParam_typ cmQUEUEPARAM;

static int queueSendPrePend(cmOBJ *obj, void *param)
{
    cmQUEUEDATA *data = (cmQUEUEDATA *)(obj->data);
    unsigned int newWp;

    newWp = data->wp + 1 < data->msgNumMax ? data->wp + 1 : 0;
    if(newWp == data->rp){
        return CM_ERR_QueueSendToFull;
    }else{
        cmQUEUEPARAM *qParam = (cmQUEUEPARAM *)param;

        *(data->msgBuf + data->wp) = qParam->msg;
        data->wp = newWp;
        return 0;
    }
}

static int queueSendPrePost(cmOBJ *obj, void *param)
{
    (void)obj;
    (void)param;
    return 0;
}

static int queueRecvPrePend(cmOBJ *obj, void *param)
{
    cmQUEUEDATA *data = (cmQUEUEDATA *)(obj->data);

    if(data->wp == data->rp){
        return CM_ERR_QueueRecvFromEmpty;
    }else{
        cmQUEUEPARAM *qParam = (cmQUEUEPARAM *)param;

        qParam->msg = *(data->msgBuf + data->rp);
        data->rp = data->rp + 1 < data->msgNumMax ? data->rp + 1 : 0;
    }

    return 0;
}

static int queueRecvPrePost(cmOBJ *obj, void *param)
{
    (void)obj;
    (void)param;
    return 0;
}

int cmQueueInit
(
    cmQUEUE *queue,
    unsigned int opt,
    unsigned int msgNum,
    unsigned long *msgBuf
)
{
    int ret;

    if((msgNum < 2) || (msgBuf == (unsigned long *)0)){
        return CM_ERR_InvalidArgument;
    }
    
    queue->data.msgBuf = msgBuf;
    queue->data.msgNumMax = msgNum;
    queue->data.rp = 0;
    queue->data.wp = 0;

    ret = cmTaskObjInit(&queue->sendObj, CM_OBJ_QUEUE_SEND, opt, queueSendPrePost, queueSendPrePend, (void*)&queue->data);
    if(ret == 0){
        ret = cmTaskObjInit(&queue->recvObj, CM_OBJ_QUEUE_SEND, opt, queueRecvPrePost, queueRecvPrePend, (void*)&queue->data);
    }

    return ret;
}

int cmQueueSend(cmQUEUE *queue, unsigned long msg, unsigned int tout)
{
    int ret;
    cmQUEUEPARAM qParam;

    qParam.msg = msg;

    ret = cmTaskObjPend(&queue->sendObj, tout, &qParam);
    if(ret == 0){
        ret = cmTaskObjPost(&queue->recvObj, (void*)0);
    }
    return ret;
}

int cmQueueRecv(cmQUEUE *queue, unsigned long *msg, unsigned int tout)
{
    int ret;
    cmQUEUEPARAM qParam;

    ret = cmTaskObjPend(&queue->recvObj, tout, &qParam);
    if(ret == 0){
        *msg = qParam.msg;
        ret = cmTaskObjPost(&queue->sendObj, (void*)0);
    }
    return ret;
}

int cmQueueFlush(cmQUEUE *queue)
{
    return -1;
}

